package cn.icanci.loopstack.bic.biz.dts.impl;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import cn.hutool.core.lang.Pair;
import cn.icanci.loopstack.bic.biz.dts.DTS;
import cn.icanci.loopstack.bic.biz.dts.GraphDtsService;
import cn.icanci.loopstack.bic.biz.service.NodeVueService;
import cn.icanci.loopstack.bic.biz.service.SnapshotService;
import cn.icanci.loopstack.bic.biz.service.UnitViewService;
import cn.icanci.loopstack.bic.common.enums.NodeTypeEnum;
import cn.icanci.loopstack.bic.common.model.base.NodeVueVO;
import cn.icanci.loopstack.bic.common.model.graph.*;

/**
 * @author icanci
 * @since 1.0 Created in 2023/09/17 16:33
 */
@Service
@DTS(UnitViewTreeVO.class)
public class UnitViewTreeGraphDtsServiceImpl implements GraphDtsService<UnitViewTreeVO> {
    @Resource
    private UnitViewService unitViewService;
    @Resource
    private SnapshotService snapshotService;
    @Resource
    private NodeVueService  nodeVueService;

    @Override
    public void dtsUnitViewTree(UnitViewTreeVO unitViewTree) {
        String systemUuid = unitViewTree.getSystemUuid();
        String useCaseUuid = unitViewTree.getUseCaseUuid();

        UnitViewVO unitViewVO = unitViewService.queryBySystemUuidAndUseCaseUuid(systemUuid, useCaseUuid);
        UnitViewVO uv = adapter2UnitViewVO(unitViewTree);
        if (unitViewVO == null) {
            unitViewService.save(uv);
        } else {
            uv.setId(unitViewVO.getId());
            uv.setUuid(unitViewVO.getUuid());
            uv.setCreateTime(unitViewVO.getCreateTime());
            uv.setDeleted(unitViewVO.isDeleted());
            uv.setEnv(unitViewVO.getEnv());
            unitViewService.save(uv);
        }
        snapshotService.refresh(systemUuid, useCaseUuid);
    }

    private UnitViewVO adapter2UnitViewVO(UnitViewTreeVO tree) {
        String systemUuid = tree.getSystemUuid();
        String useCaseUuid = tree.getUseCaseUuid();
        UnitViewVO uv = new UnitViewVO();
        uv.setSystemUuid(systemUuid);
        uv.setUseCaseUuid(useCaseUuid);

        List<UnitViewTreeRelationVO> relationModel = tree.getRelationModel();
        Pair<List<UnitEdgeVO>, List<UnitNodeVO>> pair = adapter2Pair(relationModel);
        uv.setEdges(pair.getKey());
        uv.setNodes(pair.getValue());
        return uv;
    }

    /**
     * 结对
     *
     * @param relationModel relationModel
     * @return 结对处理
     */
    private Pair<List<UnitEdgeVO>, List<UnitNodeVO>> adapter2Pair(List<UnitViewTreeRelationVO> relationModel) {
        List<NodeVueVO> nodeVueList = nodeVueService.queryAll();
        Map<String, NodeVueVO> nodeVueMap = nodeVueList.stream().collect(Collectors.toMap(NodeVueVO::getNodeUuid, nodeVueVO -> nodeVueVO));
        List<UnitEdgeVO> edges = Lists.newArrayList();
        Set<UnitNodeVO> nodes = Sets.newHashSet();

        int deep = 0;
        loopAdapter(deep, edges, nodes, relationModel, nodeVueMap);
        return new Pair<>(edges, Lists.newArrayList(nodes));
    }

    private void loopAdapter(int edgeDeep, List<UnitEdgeVO> edges, Set<UnitNodeVO> nodes, List<UnitViewTreeRelationVO> relationModel, Map<String, NodeVueVO> nodeVueMap) {
        for (UnitViewTreeRelationVO rm : relationModel) {
            nodes.add(buildSourceNode(rm, nodeVueMap.get(rm.getSourceNodeUuid())));
            nodes.add(buildTargetNode(rm, nodeVueMap.get(rm.getTargetNodeUuid())));
            edges.add(buildEdge(rm, edgeDeep));
            if (CollectionUtils.isNotEmpty(rm.getChildren())) {
                loopAdapter(++edgeDeep, edges, nodes, rm.getChildren(), nodeVueMap);
            }
        }
    }

    /**
     * 构建Source
     *
     * @param rm        rm
     * @param nodeVue nodeVue
     * @return UnitNodeVO
     */
    private UnitNodeVO buildSourceNode(UnitViewTreeRelationVO rm, NodeVueVO nodeVue) {
        UnitNodeVO node = new UnitNodeVO();
        node.setNodeUuid(rm.getSourceNodeUuid());
        node.setStyleUuid(rm.getSourceStyleUuid());
        node.setNodeDataMode(rm.getSourceNodeDataMode());
        node.setNodeDataKey(rm.getSourceNodeDataKey());
        node.setNodeType(NodeTypeEnum.CHILD);
        node.setNodeVue(nodeVue.getUuid());
        return node;
    }

    /**
     * 构建Target
     *
     * @param rm rm
     * @param nodeVue nodeVue
     * @return UnitNodeVO
     */
    private UnitNodeVO buildTargetNode(UnitViewTreeRelationVO rm, NodeVueVO nodeVue) {
        UnitNodeVO node = new UnitNodeVO();
        node.setNodeUuid(rm.getTargetNodeUuid());
        node.setStyleUuid(rm.getTargetStyleUuid());
        node.setNodeDataMode(rm.getTargetNodeDataMode());
        node.setNodeDataKey(rm.getTargetNodeDataKey());
        node.setNodeType(NodeTypeEnum.CHILD);
        node.setNodeVue(nodeVue.getUuid());
        return node;
    }

    /**
     * 构建Edge
     *
     * @param rm rm
     * @return UnitEdgeVO
     */
    private UnitEdgeVO buildEdge(UnitViewTreeRelationVO rm, int edgeDeep) {
        UnitEdgeVO edge = new UnitEdgeVO();
        edge.setHoverName(rm.getHoverName());
        edge.setSourceUuid(rm.getSourceNodeUuid());
        edge.setTargetUuid(rm.getTargetNodeUuid());
        edge.setStyleUuid(rm.getEdgeStyleUuid());
        edge.setDeep(edgeDeep);
        return edge;
    }
}
